home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / ARGONET / PD / SOUND / REPLAYER.SPK / c / driver < prev    next >
Text File  |  1998-08-24  |  11KB  |  348 lines

  1.  
  2. /* driver.c
  3.  
  4.    Replayer -- audio player
  5.    Copyright (c) 1997/8 Mark Seaborn <mseaborn@argonet.co.uk>
  6.  
  7.    Contains functions for dealing with Replay sound drivers.  Allows the
  8.    drivers to be used for tasks outside of playing Replay files.
  9. */
  10.  
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include "swis.h"
  14. #include "OS:os.h"
  15. #include "OS:osbyte.h"
  16. #include "OS:osfile.h"
  17. #include "OS:osmodule.h"
  18.  
  19. #ifdef MemCheck_MEMCHECK
  20. #include "MemCheck:MemCheck.h"
  21. #endif
  22.  
  23. #include "replaydriver.h"
  24.  
  25.  
  26. /* Declarations */
  27.  
  28. #define DYNAMIC_AREA_NAME    "Replay sound data"
  29. #define SOUND_CHECK_TIME    100 /* centiseconds */
  30.  
  31.  
  32. /* Loading and freeing drivers. */
  33.  
  34. /* Load the Replay sound driver whose filename is given, and return this
  35.    driver.  Returns 0 for failure (driver not found, or out of memory).
  36.    You can pass the full pathname of the driver or just the leafname. */
  37. replaydriver_driver *replaydriver_load(const char *filename)
  38. {
  39.   replaydriver_driver *driver = 0;
  40.   int exists, size;
  41.   char *copy = 0;
  42.  
  43.   /* Find size of file. */
  44.   xosfile_read_stamped(filename, &exists, 0, 0, &size, 0, 0);
  45.   if(~exists & fileswitch_IS_FILE) {
  46.     /* If the file wasn't found, prepend a directory name. */
  47.     int len = strlen(filename);
  48.     copy = malloc(strlen(replaydriver_DRIVER_PREFIX) + len + 1);
  49.     if(!copy) goto fail;
  50.     strcpy(copy, replaydriver_DRIVER_PREFIX);
  51.     memcpy(copy + strlen(replaydriver_DRIVER_PREFIX), filename, len + 1);
  52.     filename = copy;
  53.  
  54.     /* Try getting the info again. */
  55.     if(xosfile_read_stamped(filename, 0, 0, 0, &size, 0, 0)) goto fail;
  56.   }
  57.   /* Allocate memory from RMA. */
  58.   if(xosmodule_alloc(size, (void **) &driver) || !driver) goto fail;
  59.  
  60.   /* Load code.  The following line should be StrongARM compatible.  It is
  61.      the same as this OSLib SWI call, but with bit 31 (sync cache) set:
  62.        osfile_load_stamped(code_filename, (byte *) code, 0, 0, 0, 0); */
  63.   if(_swix(OS_File, _IN(0)|_IN(1)|_IN(2)|_IN(3), 12,
  64.     filename, driver, 1u<<31)) goto fail;
  65.  
  66.   /* Register the driver's block with MemCheck, as we need to access it
  67.      directly later to set and read various things. */
  68. #ifdef MemCheck_MEMCHECK
  69.   MemCheck_RegisterMiscBlock(driver, size);
  70. #endif
  71.   free(copy);
  72.   return driver;
  73.  
  74. fail:
  75.   free(copy);
  76.   if(driver) xosmodule_free(driver);
  77.   return 0;
  78. }
  79.  
  80. /* Frees the space used by the Replay sound driver. */
  81. void replaydriver_destroy(replaydriver_driver *driver)
  82. {
  83.   if(!driver) return;
  84.  
  85.   xosmodule_free(driver);
  86. #ifdef MemCheck_MEMCHECK
  87.   MemCheck_UnRegisterMiscBlock(driver);
  88. #endif
  89. }
  90.  
  91.  
  92. /* Creating and freeing control blocks. */
  93.  
  94. /* Allocate a control block for the driver.  Returns 0 for failure.  All
  95.    fields are zeroed before returning, except for the quality field (set to
  96.    maximum quality). */
  97. replaydriver_control *replaydriver_control_create(void)
  98. {
  99.   replaydriver_control *control;
  100.  
  101.   /* Allocate a block in the RMA. */
  102.   if(xosmodule_alloc(sizeof(replaydriver_control), (void **) &control)
  103.     || !control) return 0;
  104. #ifdef MemCheck_MEMCHECK
  105.   MemCheck_RegisterMiscBlock(control, sizeof(replaydriver_control));
  106. #endif
  107.  
  108.   /* Zero all fields. */
  109.   memset(control, 0, sizeof(replaydriver_control));
  110.   /* Set other defaults. */
  111.   control->data.quality = 4;
  112.  
  113.   return control;
  114. }
  115.  
  116. /* Free a previously allocated control block. */
  117. void replaydriver_control_destroy(replaydriver_control *control)
  118. {
  119.   if(!control) return;
  120.  
  121.   /* Free and deregister the block. */
  122.   xosmodule_free(control);
  123. #ifdef MemCheck_MEMCHECK
  124.   MemCheck_UnRegisterMiscBlock(control);
  125. #endif
  126. }
  127.  
  128.  
  129. /* Allocating and freeing sound buffers and temporary space. */
  130.  
  131. /* Allocates two sound buffers, when given the size each buffer must be.
  132.    Fills the driver given with the locations of the buffers.  Returns 0 for
  133.    failure. */
  134. replaydriver_buffer *replaydriver_buffer_create(int single_size,
  135.     replaydriver_driver *driver)
  136. {
  137.   replaydriver_buffer *buf = 0;
  138.   size_t total_size;
  139.   int os_version, i;
  140.   void *buffers[2];
  141.   if(!driver || single_size <= 0) return 0;
  142.  
  143.   /* Allocate info block. */
  144.   buf = malloc(sizeof(replaydriver_buffer));
  145.   if(!buf) return 0;
  146.   buf->single_size = single_size;
  147.   buf->temp_size = 0;
  148.  
  149.   /* Allocate space for the buffers. */
  150.   total_size = (single_size + 4) * 2;
  151.   if(xos_byte(129, 0, 0xFF, &os_version, 0)) goto fail;
  152.   if(os_version >= 0xA5) {
  153.     /* Running under RISC OS 3.5+, so use a dynamic area. */
  154.     if(xosdynamicarea_create(-1, total_size, (byte *) -1, 1<<7,
  155.     total_size * 4 /* Max size */, 0, 0, DYNAMIC_AREA_NAME,
  156.     &buf->dynarea, (byte **) &buf->buffer, 0))
  157.         goto use_rma_buffer;
  158.   }
  159.   else {
  160.     /* Dynamic areas not available, so allocate from module area. */
  161.   use_rma_buffer:
  162.     if(xosmodule_alloc(total_size, &buf->buffer) || !buf->buffer) goto fail;
  163.     buf->dynarea = -1;
  164.   }
  165. #ifdef MemCheck_MEMCHECK
  166.   MemCheck_RegisterMiscBlock(buf->buffer, total_size);
  167. #endif
  168.  
  169.   /* Initialise buffers and attach to the driver. */
  170.   buffers[0] = (char *) buf->buffer;
  171.   buffers[1] = (char *) buf->buffer + single_size + 4;
  172.   for(i=0; i<2; ++i) {
  173.     replaydriver_set_buffer(driver, i, buffers[i]);
  174.     ((int *) buffers[i])[1] = 1; /* Set state to unfilled. */
  175.     *(int *) ((char *) buffers[i] + single_size) =
  176.         replaydriver_BUFFER_CHECK_WORD;
  177.   }
  178.  
  179.   /* Return successfully. */
  180.   return buf;
  181.  
  182.   /* Return unsuccessfully. */
  183. fail:
  184.   free(buf);
  185.   return 0;
  186. }
  187.  
  188. /* Frees a previously-allocated set of sound buffers. */
  189. void replaydriver_buffer_destroy(replaydriver_buffer *buf)
  190. {
  191.   if(!buf) return;
  192.  
  193.   /* Free the buffer itself. */
  194.   if(buf->dynarea != -1) {
  195.     /* Free the dynamic area. */
  196.     xosdynamicarea_delete(buf->dynarea);
  197.   }
  198.   else {
  199.     /* Free the module area block. */
  200.     xosmodule_free(buf->buffer);
  201.   }
  202. #ifdef MemCheck_MEMCHECK
  203.   MemCheck_UnRegisterMiscBlock(buf->buffer);
  204. #endif
  205.  
  206.   /* Free the buffer info block. */
  207.   free(buf);
  208. }
  209.  
  210. /* Allocates a temporary data block.  Takes an already-allocated buffer
  211.    object, so that the new block can be tacked onto the end of an existing
  212.    dynamic area.  Only one temporary block can be used for each buffer at a
  213.    time.  Returns 0 for failure. */
  214. void *replaydriver_temp_alloc(replaydriver_buffer *buf, size_t size)
  215. {
  216.   void *block;
  217.  
  218.   if(buf && buf->dynarea != -1) {
  219.     /* If the sound buffers use a dynamic area, extend the area.  If an
  220.        error occurs, fall back to using the module area. */
  221.     int page_size, old_size;
  222.     if(xos_read_dynamic_area(buf->dynarea, (byte **) &block, &old_size, 0))
  223.       goto use_rma_block;
  224.     block = (char *) block + old_size;
  225.     /* Round the size up to the nearest page (so that calling
  226.        OS_ChangeDynamicArea again later doesn't cause wastage). */
  227.     if(xos_read_mem_map_info(&page_size, 0)) goto use_rma_block;
  228.     size = ((size + page_size - 1) / page_size) * page_size;
  229.     if(xos_change_dynamic_area(buf->dynarea, size, (int *) &size))
  230.       goto use_rma_block;
  231.     buf->temp_size = size;
  232.   }
  233.   else {
  234.     /* Otherwise allocate a fresh block in the module area. */
  235.   use_rma_block:
  236.     if(xosmodule_alloc(size, &block) || !block) return 0; /* Fail */
  237.   }
  238. #ifdef MemCheck_MEMCHECK
  239.   MemCheck_RegisterMiscBlock(block, size);
  240. #endif
  241.  
  242.   return block; /* Success */
  243. }
  244.  
  245. /* Free a previously-allocated temporary block. */
  246. void replaydriver_temp_free(replaydriver_buffer *buf, void *block)
  247. {
  248.   if(buf && buf->dynarea != -1) {
  249.     /* Return the dynamic area to its original size. */
  250.     xos_change_dynamic_area(buf->dynarea, -buf->temp_size, 0);
  251.     buf->temp_size = 0;
  252.   }
  253.   else {
  254.     /* Free the block in the module area. */
  255.     if(block) xosmodule_free(block);
  256.   }
  257. #ifdef MemCheck_MEMCHECK
  258.   MemCheck_UnRegisterMiscBlock(block);
  259. #endif
  260. }
  261.  
  262.  
  263. /* Performing a timing check. */
  264.  
  265. /* Begin a timing check.  Requires a pointer to a state variable (used to
  266.    store a time).  You can do other things in the mean time; when you are
  267.    ready, call replaydriver_timecheck_finish(). */
  268. void replaydriver_timecheck_start(replaydriver_driver *driver,
  269.     replaydriver_control *control, replaydriver_timecheck_state *state)
  270. {
  271.   if(!driver || !control) return;
  272.  
  273.   replaydriver_play_entry(driver, control, 1);
  274.   /* Work out the time to wait until. */
  275.   *state = os_read_monotonic_time() + SOUND_CHECK_TIME;
  276.   if(!*state) *state = 1; /* Once in a blue moon; state must be non-zero. */
  277. }
  278.  
  279. /* Wait for the timing check to finish. */
  280. void replaydriver_timecheck_finish(replaydriver_driver *driver,
  281.     replaydriver_control *control, replaydriver_timecheck_state *state)
  282. {
  283.   if(!driver || !control) return;
  284.  
  285.   /* If time checks are necessary, wait for it to finish. */
  286.   if(~replaydriver_get_flags(driver) & replaydriver_NO_SOUND_CHECK)
  287.     { while((*state - os_read_monotonic_time()) > 0) { /* Nothing! */ } }
  288.   replaydriver_stop(driver, control);
  289.   *state = 0;
  290. }
  291.  
  292. /* End the sound check prematurely (eg. an error may have occurred). */
  293. void replaydriver_timecheck_abort(replaydriver_driver *driver,
  294.     replaydriver_control *control, replaydriver_timecheck_state *state)
  295. {
  296.   if(!driver || !control) return;
  297.   if(*state) {
  298.     replaydriver_stop(driver, control);
  299.     *state = 0;
  300.   }
  301. }
  302.  
  303.  
  304. /* Stopping. */
  305.  
  306. /* Stop playing.  Also resets buffers to unfilled. */
  307. void replaydriver_stop(replaydriver_driver *driver,
  308.     replaydriver_control *control)
  309. {
  310.   if(!driver || !control) return;
  311.  
  312.   /* Tell driver. */
  313.   replaydriver_veneer((unsigned) control, 0, (void *) &driver->stop);
  314.  
  315.   /* Set buffers to unfilled. */
  316.   ((int *) replaydriver_get_buffer(driver, 0))[1] = 1;
  317.   ((int *) replaydriver_get_buffer(driver, 1))[1] = 1;
  318. }
  319.  
  320.  
  321. /* Feeding data. */
  322.  
  323. /* Feeds the driver more data.  Also keeps track of which buffer will become
  324.    empty next, so that its status word can be used as a poll word. */
  325. void replaydriver_feed(replaydriver_driver *driver,
  326.     replaydriver_control *control, void *data, size_t size)
  327. {
  328.   int next_buffer;
  329.   if(!driver || !control) return;
  330.  
  331.   /* Which buffer will become empty next?  The one that's full now (they
  332.      can't both be full). */
  333.   if(!*replaydriver_buffer_empty(driver, 0)) next_buffer = 0;
  334.   else if(!*replaydriver_buffer_empty(driver, 1)) next_buffer = 1;
  335.   else next_buffer = -1; /* Neither are full. */
  336.  
  337.   /* Do the actual buffer filling. */
  338.   replaydriver_veneer((unsigned) data, size, (void *) &(driver)->feed);
  339.  
  340.   if(next_buffer == -1) {
  341.     /* Try again, which buffer will become empty next?  The one that has
  342.        just become full (only one must be full). */
  343.     if(!*replaydriver_buffer_empty(driver, 0)) next_buffer = 0;
  344.     else if(!*replaydriver_buffer_empty(driver, 1)) next_buffer = 1;
  345.   }
  346.   control->extra.next_buffer = next_buffer;
  347. }
  348.